﻿
using System.Collections.Generic;
using System;
using System.Linq;
using System.IO;
using System.Text;
using System.Reflection;
using TEngine;
using System.Collections;

namespace GameLogic
{
    /// <summary>
    /// TypeInfo的类型
    /// </summary>
    public enum TypeInfoType
    {
        /// <summary>
        /// 默认类型，为D_TYPE类型
        /// </summary>
        Default = 0,
        /// <summary>
        /// 列表类型，为List<D_TYPE>类型
        /// </summary>
        List,
        /// <summary>
        /// APIBase的类型
        /// </summary>
        APIBase
    }

    /// <summary>
    /// TypeInfo类，用于指定PropertySequence时使用，方便序列化与反序列化
    /// </summary>
    public class TypeInfo
    {
        public D_TYPE SingleType { get; } = D_TYPE.NONE;
        public List<D_TYPE> TypeList { get; }
        public APIBase Packet { get; }

        public TypeInfoType Type => SingleType != D_TYPE.NONE ? TypeInfoType.Default : (TypeList != null ? TypeInfoType.List : TypeInfoType.APIBase);

        public TypeInfo(D_TYPE singleType)
        {
            SingleType = singleType;
        }

        public TypeInfo(List<D_TYPE> typeList)
        {
            TypeList = typeList;
        }
        public TypeInfo(APIBase packet)
        {
            Packet = packet;
        }

        //支持隐式转换，简化代码
        public static implicit operator TypeInfo(D_TYPE type) => new TypeInfo(type);
        public static implicit operator TypeInfo(List<D_TYPE> typeList) => new TypeInfo(typeList);
        public static implicit operator TypeInfo(D_TYPE[] typeArray) => new TypeInfo(typeArray.ToList());
        public static implicit operator TypeInfo(APIBase d) => new TypeInfo(d);
    }

    /// <summary>
    /// Socket包的基类
    /// </summary>
    public abstract class APIBase
    {
        /// <summary>
        /// 是否是新的socket包，包含新包头，默认为true
        /// </summary>
        public bool HasNewHead { get; set; } = true;

        #region API的长度
        private int? _length;

        /// <summary>
        /// API包的长度
        /// </summary>
        public int APILength
        {
            get
            {
                if (_length == null)
                {
                    _length = CalculatePropertySequenceBytes();
                }
                return _length.Value;
            }
        }

        /// <summary>
        /// 计算属性序列字节数
        /// </summary>
        /// <returns>返回长度int</returns>
        private int CalculatePropertySequenceBytes()
        {
            return PropertySequence.Sum((item) =>
            {
                var (type, propName) = item;
                int size = 0;
                if (type.Type == TypeInfoType.Default)
                {
                    size = TypeSizeHelper.GetTypeSize(type.SingleType);
                }
                else if (type.Type == TypeInfoType.List)
                {
                    size = type.TypeList.Sum(t => TypeSizeHelper.GetTypeSize(t));
                }
                else
                {
                    size = type.Packet.APILength;
                }
                //Log.Info("propName:{0}, size:{1}", propName, size);
                return size;
            });
        }
        #endregion

        #region 数据列表转换

        /// <summary>
        /// 属性映射列表，需要在子类中重写
        /// </summary>
        public virtual List<(TypeInfo type, string propertyName)> PropertySequence => new List<(TypeInfo, string)>();

        /// <summary>
        /// 最终转换的数据列表
        /// </summary>
        public List<(D_TYPE type, object value)> DataList
        {
            get
            {
                return TransformDataList(PropertySequence);
            }
        }

        /// <summary>
        /// 用于转换List的数据列表
        /// </summary>
        /// <param name="dataList"></param>
        /// <returns></returns>
        private List<(D_TYPE type, object value)> TransformDataList(List<(TypeInfo type, string propName)> dataList)
        {
            var result = new List<(D_TYPE, object)>();

            foreach (var (type, propName) in dataList)
            {
                var propertyValue = GetType().GetField(propName)?.GetValue(this);
                TransformValue(type, propertyValue, result);
            }
            return result;
        }
        /// <summary>
        /// 用于转换单个数据列表
        /// </summary>
        private void TransformValue(TypeInfo type, object value, List<(D_TYPE, object)> result)
        {
            if (type.Type == TypeInfoType.APIBase)
            {
                result.AddRange(type.Packet.DataList);
            }
            else if (type.Type == TypeInfoType.List)
            {
                if (value is IEnumerable enumerable) // 检查是否可枚举
                {
                    int i = 0;
                    foreach (var item in enumerable)
                    {
                        if (i < type.TypeList.Count)
                        {
                            TransformValue(type.TypeList[i], item, result);
                            i++;
                        }
                        else
                        {
                            break; // 防止越界
                        }
                    }
                }
                else
                {
                    throw new ArgumentException("Expected a collection but got a non-enumerable value.");
                }
            }
            else
            {
                result.Add((type.SingleType, value ?? 0));
            }
        }
        #endregion
    }

    /// <summary>
    /// 发送的包都应继承SendPack
    /// </summary>
    public abstract class SendPack : APIBase
    {
        public uint CmdID => GetCmdID();

        /// <summary>
        /// Send的包必须实现该方法，用于指明包的CmdID
        /// </summary>
        /// <returns></returns>
        protected abstract uint GetCmdID();

        /// <summary>
        /// 把APIBase对象转换为字节数组，用于发包
        /// </summary>
        /// <returns></returns>
        public byte[] ToArray()
        {
            return Write();
        }

        /// <summary>
        /// 重写该方法来提供包的特殊写入处理
        /// </summary>
        protected virtual byte[] Write()
        {
            var writer = new BinaryPacketWriter();
            Write(writer);
            return writer.ToArray();
        }

        private byte[] Write(BinaryPacketWriter writer)
        {
            foreach (var (type, value) in DataList)
            {
                try
                {
                    writer.WriteData(type, value);
                }
                catch (Exception ex)
                {
                    Log.Error($"APIBase.Write Error: {ex.Message}");
                }
            }
            return writer.ToArray();
        }

        /// <summary>
        /// 用于构建发送的二进制数据包，组合包头和包体
        /// </summary>
        /// <typeparam name="T">泛型类，该类约束必须为SendPack的派生类</typeparam>
        /// <param name="packet">SendPack派生类实例</param>
        /// <returns></returns>
        public static byte[] SerializePacket<T>(T packet) where T : SendPack
        {
            if (packet == null)
            {
                Log.Error("SerializePacket: packet is null.");
                return Array.Empty<byte>();
            }
            try
            {
                byte[] bodyData = packet.ToArray();

                if (packet.HasNewHead)
                {
                    NewHeadSend newHead = new NewHeadSend() { cmdId = packet.CmdID };
                    newHead.bodylen = (uint)(bodyData.Length + newHead.APILength);
                    byte[] newHeadData = newHead.ToArray();

                    byte[] oldHeadData = new OldHeadSend
                    {
                        cmdId = SocketDefinition.NEW_HEAD_IDENTIFY,
                        bodylen = (ushort)(newHeadData.Length + bodyData.Length)
                    }.ToArray();
                    return GameUtility.CombineBytes(oldHeadData, newHeadData, bodyData);
                }
                else
                {
                    byte[] oldHeadData = new OldHeadSend
                    {
                        cmdId = packet.CmdID,
                        bodylen = (ushort)bodyData.Length
                    }.ToArray();
                    return GameUtility.CombineBytes(oldHeadData, bodyData);
                }
            }
            catch (Exception ex)
            {
                Log.Error($"SerializePacket Error: {ex.Message}");
                return Array.Empty<byte>();
            }
        }
    }

    /// <summary>
    /// 接收的包都应继承ReceivePack
    /// </summary>
    public class ReceivePack : APIBase
    {
        /// <summary>
        /// 外部调用的接口，接收字节数组并转换为ReceivePack对象
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public ReceivePack ToReceivePack(byte[] data)
        {
            return Read(data);
        }

        /// <summary>
        /// 重写该方法来提供包的特殊处理
        /// </summary>
        public virtual ReceivePack Read(byte[] data)
        {
            var reader = new BinaryPacketReader(data);
            return ReadReader(reader);
        }

        public ReceivePack ReadReader(BinaryPacketReader reader)
        {
            foreach (var (type, propName) in PropertySequence)
            {
                object value = null;
                if (type.Type == TypeInfoType.Default)
                    value = reader.ReadData(type.SingleType);
                else if (type.Type == TypeInfoType.List)
                    value = reader.ReadData(type.TypeList);
                else if (type.Type == TypeInfoType.APIBase)
                    value = reader.ReadDataPack((ReceivePack)type.Packet);

                FieldInfo fieldInfo = GetType().GetField(propName);
                if (fieldInfo == null)
                {
                    Log.Error($"找不到字段: {propName}");
                    return this;
                }
                try
                {
                    fieldInfo.SetValue(this, value);
                }
                catch (Exception ex)
                {
                    Log.Error($"设置字段 {propName} 失败: {ex.Message}");
                }
            }
            return this;
        }
    }

    #region 二进制数据，读写序列化反序列化
    public class BinaryPacketReader
    {
        private readonly BinaryReader _reader;

        public BinaryPacketReader(byte[] data)
        {
            _reader = new BinaryReader(new MemoryStream(data), Encoding.UTF8);
        }

        public object ReadData(D_TYPE type)
        {
            try
            {
                switch (type)
                {
                    case D_TYPE.WORD:
                        return _reader.ReadUInt16();
                    case D_TYPE.WORD8:
                    case D_TYPE.BOOL8:
                        return _reader.ReadByte();
                    case D_TYPE.DWORD:
                    case D_TYPE.UINT:
                    case D_TYPE.USER_ID_PTR:
                    case D_TYPE.SERVER_ID_PTR:
                        return _reader.ReadUInt32();
                    case D_TYPE.SHORT:
                        return _reader.ReadInt16();
                    case D_TYPE.INT:
                    case D_TYPE.COLORREF:
                    case D_TYPE.BOOL:
                        return _reader.ReadInt32();
                    case D_TYPE.INT64:
                        return _reader.ReadInt64();
                    case D_TYPE.UINT64:
                        return _reader.ReadUInt64();
                    case D_TYPE.TCHAR10:
                        return ReadString(10);
                    case D_TYPE.TCHAR16:
                        return ReadString(16);
                    case D_TYPE.TCHAR20:
                        return ReadString(20);
                    case D_TYPE.TCHAR24:
                        return ReadString(24);
                    case D_TYPE.TCHAR32:
                        return ReadString(32);
                    case D_TYPE.TCHAR40:
                        return ReadString(40);
                    case D_TYPE.TCHAR64:
                        return ReadString(64);
                    case D_TYPE.TCHAR128:
                        return ReadString(128);
                    case D_TYPE.TCHAR256:
                        return ReadString(256);
                    default:
                        throw new NotSupportedException($"Unsupported type: {type}.");
                }
            }
            catch (Exception ex)
            {
                Log.Error($"BinaryPacketReader ReadData Error，Msg:{ex.Message}");
                return 0;
            }
        }

        public List<object> ReadData(List<D_TYPE> types)
        {
            var res = new List<object>();
            foreach (var type in types)
            {
                res.Add(ReadData(type));
            }
            return res;
        }

        public ReceivePack ReadDataPack(ReceivePack api)
        {
            // 记录当前位置
            long startPos = _reader.BaseStream.Position;

            // 读取API包
            var result = api.ReadReader(this);

            // 计算实际读取的字节数
            int bytesRead = (int)(_reader.BaseStream.Position - startPos);

            // 如果API包没有正确读取所有数据，调整位置
            if (bytesRead < api.APILength)
            {
                _reader.BaseStream.Position = startPos + api.APILength;
            }

            return result;
        }

        public string ReadString(int length)
        {
            byte[] bytes = _reader.ReadBytes(length);
            Encoding defultCoding = Encoding.GetEncoding(SocketDefinition.DEFAULT_ENCODING_CODEPAGE);
            return defultCoding.GetString(bytes, 0, length).TrimEnd('\0');
        }

        /// <summary>
        /// 检查是否还有剩余数据未读取
        /// </summary>
        public bool HasRemainingData()
        {
            return _reader.BaseStream.Position < _reader.BaseStream.Length;
        }

        /// <summary>
        /// 获取剩余未读取的字节数长度
        /// </summary>
        public int GetRemainingBytesLen()
        {
            return (int)(_reader.BaseStream.Length - _reader.BaseStream.Position);
        }
    }

    public class BinaryPacketWriter
    {
        private readonly BinaryWriter _writer;
        private readonly MemoryStream _stream;

        public BinaryPacketWriter()
        {
            _stream = new MemoryStream();
            _writer = new BinaryWriter(_stream, Encoding.UTF8);
        }
        public void WriteData(D_TYPE type, object value)
        {
            try
            {
                switch (type)
                {
                    case D_TYPE.WORD:
                        _writer.Write(Convert.ToUInt16(value));
                        break;
                    case D_TYPE.WORD8:
                    case D_TYPE.BOOL8:
                    case D_TYPE.BYTE:
                        _writer.Write(Convert.ToByte(value));
                        break;
                    case D_TYPE.DWORD:
                    case D_TYPE.UINT:
                    case D_TYPE.USER_ID_PTR:
                    case D_TYPE.SERVER_ID_PTR:
                        _writer.Write(Convert.ToUInt32(value));
                        break;
                    case D_TYPE.SHORT:
                        _writer.Write(Convert.ToInt16(value));
                        break;
                    case D_TYPE.INT:
                    case D_TYPE.COLORREF:
                    case D_TYPE.BOOL:
                        _writer.Write(Convert.ToInt32(value));
                        break;
                    case D_TYPE.INT64:
                        _writer.Write(Convert.ToInt64(value));
                        break;
                    case D_TYPE.UINT64:
                        _writer.Write(Convert.ToUInt64(value));
                        break;
                    case D_TYPE.TCHAR10:
                        WriteFixedString(value as string, 10);
                        break;
                    case D_TYPE.TCHAR16:
                        WriteFixedString(value as string, 16);
                        break;
                    case D_TYPE.TCHAR20:
                        WriteFixedString(value as string, 20);
                        break;
                    case D_TYPE.TCHAR24:
                        WriteFixedString(value as string, 24);
                        break;
                    case D_TYPE.TCHAR32:
                        WriteFixedString(value as string, 32);
                        break;
                    case D_TYPE.TCHAR40:
                        WriteFixedString(value as string, 40);
                        break;
                    case D_TYPE.TCHAR64:
                        WriteFixedString(value as string, 64);
                        break;
                    case D_TYPE.TCHAR128:
                        WriteFixedString(value as string, 128);
                        break;
                    case D_TYPE.TCHAR256:
                        WriteFixedString(value as string, 256);
                        break;
                    default:
                        throw new NotSupportedException($"Unsupported type: {type}.");
                }
            }
            catch (Exception ex)
            {
                Log.Error($"BinaryPacketWriter WriteData Error，Msg:{ex.Message}");
            }
        }

        private void WriteFixedString(string value, int length)
        {
            if (value == null)
                value = string.Empty;
            var bytes = Encoding.GetEncoding(SocketDefinition.DEFAULT_ENCODING_CODEPAGE).GetBytes(value);  //默认编码，GBK编码
            if (bytes.Length >= length)
            {
                _writer.Write(bytes, 0, length);
            }
            else
            {
                _writer.Write(bytes);
                // 填充剩余的字节为0
                for (int i = bytes.Length; i < length; i++)
                {
                    _writer.Write((byte)0);
                }
            }
        }

        public byte[] ToArray()
        {
            _writer.Flush();
            return _stream.ToArray();
        }
    }
    #endregion
}
